package top.codedance.iotp.common.protocol;

import top.codedance.iotp.common.entity.CommonEntity;
import cd.io.netty.buffer.ByteBuf;
import cd.io.netty.channel.ChannelHandlerContext;
import cd.io.netty.handler.codec.ByteToMessageCodec;
import org.apache.log4j.Logger;

import java.util.List;

public class CommonDecoderCodec extends ByteToMessageCodec<CommonEntity> {

    private static Logger logger;
    public static final byte HEAD_TAG = 0x1B;

    public CommonDecoderCodec(Logger logger){
        this.logger = logger;
    }

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, CommonEntity commonEntity, ByteBuf byteBuf) throws Exception {
        byte head = commonEntity.getHead();
        short command = commonEntity.getCommand();
        long version = commonEntity.getVersion();
        byte[] body = commonEntity.getBody();
        int packageLeng = Byte.SIZE / 8 + Integer.SIZE / 8 + Short.SIZE / 8 + Long.SIZE / 8;
        if (body != null) {
            packageLeng = packageLeng + body.length;
        }

        logger.debug("encode: ");
        logger.debug("   head: "+head);
        logger.debug("   packageLeng: "+packageLeng);
        logger.debug("   command: "+command);
        logger.debug("   version: "+version);
        if (body != null) {
            logger.debug("   body: " + body.length);
        }

        byteBuf.writeByte(head);
        byteBuf.writeInt(packageLeng);
        byteBuf.writeShort(command);
        byteBuf.writeLong(version);
        if (body != null) {
            byteBuf.writeBytes(body);
        }
    }

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        while (true) {
            logger.debug("decode: ");
            int leng = byteBuf.readableBytes();
            logger.debug("   leng: " + leng);
            if (leng < Byte.SIZE / 8) {
                break;
            }
            byteBuf.markReaderIndex();
            byte head = byteBuf.readByte();
            logger.debug("   head: " + head);
            if (head != HEAD_TAG) {
                byteBuf.skipBytes(Byte.SIZE / 8);
                byteBuf.markReaderIndex();
                break;
            }
            if (leng < (Byte.SIZE / 8 + Integer.SIZE / 8)) {
                byteBuf.resetReaderIndex();
                break;
            }
            int packageLength = byteBuf.readInt();
            logger.debug("   packageLength: " + packageLength);
            if (leng < packageLength) {
                byteBuf.resetReaderIndex();
                break;
            }
            short command = byteBuf.readShort();
            logger.debug("   command: " + command);
            long version = byteBuf.readLong();
            logger.debug("   version: " + version);
            int bodyLength = packageLength - (Byte.SIZE / 8 + Integer.SIZE / 8 + Short.SIZE / 8 + Long.SIZE / 8);
            byte[] body = null;
            if(bodyLength > 0) {
                body = new byte[bodyLength];
                byteBuf.readBytes(body);
                logger.debug("   bodyLength: " + body.length);
            }

            CommonEntity commonEntity = new CommonEntity();
            commonEntity.setHead(head);
            commonEntity.setPackageLength(packageLength);
            commonEntity.setCommand(command);
            commonEntity.setVersion(version);
            commonEntity.setBody(body);
            list.add(commonEntity);
        }
    }
}
